package aole.codeflow;

import java.io.File;
import java.io.IOException;

import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.input.KeyEvent;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;

import org.xml.sax.SAXException;

import aole.codeflow.util.XML;

public class CodeFlow extends Application {
	private Code		selectedCode;
	private TextField	txtSelection	= new TextField();
	private Label		lblSelection	= new Label();

	/**
	 * @param args
	 */
	public static void main( String[] args ) {
		launch( args );
	}

	@Override
	public void start( Stage stage ) throws Exception {
		// create flow
		ObservableList< Code > data = createFlow();
		// show flow
		TableView< Code > table = createTable( data );

		// show selection controls
		HBox hbox = getSelectionControls( data, table );

		BorderPane root = new BorderPane();
		root.setCenter( table );
		root.setBottom( hbox );

		stage.setScene( new Scene( root, 800, 600 ) );
		stage.show();
	}

	private HBox getSelectionControls( final ObservableList< Code > data,
			final TableView< Code > table ) {

		txtSelection.setOnKeyReleased( new EventHandler< KeyEvent >() {
			@Override
			public void handle( KeyEvent ke ) {
				if( selectedCode != null ) {
					selectedCode.setCode( txtSelection.getText() );
					// refresh tableview
					table.getColumns().get( 0 ).setVisible( false );
					table.getColumns().get( 0 ).setVisible( true );
				}
			}
		} );

		table.setOnMousePressed( new EventHandler< MouseEvent >() {
			@Override
			public void handle( MouseEvent me ) {
				selectCode( table, table.getSelectionModel().getSelectedItem() );
			}
		} );

		Button btninsert = new Button( "Insert After" );
		btninsert.setOnAction( new EventHandler< ActionEvent >() {
			@Override
			public void handle( ActionEvent ae ) {
				Code c;
				int index = table.getSelectionModel().getSelectedIndex() + 1;
				if( index == 0 ) {
					int size = data.size();
					size = (size + 1) * 10;
					c = new Code( size, "New Statement" );
					data.add( c );
				} else {
					c = new Code( 1, "New Statement" );
					data.add( index, c );
					correctSequence( data );
				}
				selectCode( table, c );
				txtSelection.requestFocus();
			}
		} );

		Button btnDelete = new Button( "Delete" );
		btnDelete.setOnAction( new EventHandler< ActionEvent >() {
			@Override
			public void handle( ActionEvent ae ) {
				if( selectedCode != null ) {
					data.remove( selectedCode );
					correctSequence( data );
					selectCode( table, null );
				}
			}
		} );

		Button btnSave = new Button( "Save" );
		btnSave.setOnAction( new EventHandler< ActionEvent >() {
			@Override
			public void handle( ActionEvent ae ) {
				File f = new File( "test.xml" );
				try {
					XML.save( data, f );
				} catch( ParserConfigurationException | TransformerException e ) {
					System.out.println( "Error saving xml file" );
					e.printStackTrace();
				}
			}
		} );

		Button btnLoad = new Button( "Load" );
		btnLoad.setOnAction( new EventHandler< ActionEvent >() {
			@Override
			public void handle( ActionEvent ae ) {
				File f = new File( "test.xml" );
				try {
					data.removeAll( data );
					XML.load( data, f );
				} catch( ParserConfigurationException | SAXException
						| IOException e ) {
					System.out.println("Error loading XML");
					e.printStackTrace();
				}
			}
		} );

		HBox hbox = new HBox();
		hbox.getChildren().addAll( lblSelection, txtSelection, btninsert,
				btnDelete, btnSave, btnLoad );

		return hbox;
	}

	protected void selectCode( TableView< Code > table, Code c ) {
		selectedCode = c;
		table.getSelectionModel().select( c );
		if( c != null ) {
			txtSelection.setText( c.getCode() );
			lblSelection.setText( "<" + c.getSerial() + ">" );
		} else {
			txtSelection.setText( "<no selection>" );
			lblSelection.setText( "<>" );
		}
	}

	protected void correctSequence( ObservableList< Code > data ) {
		int i = 10;
		for( Code d: data ) {
			d.setSerial( i );
			i += 10;
		}
	}

	@SuppressWarnings("unchecked")
	private TableView< Code > createTable( ObservableList< Code > data ) {
		TableColumn< Code, Integer > serialCol = new TableColumn<>( "SR" );
		serialCol
				.setCellValueFactory( new PropertyValueFactory< Code, Integer >(
						"serial" ) );
		TableColumn< Code, String > codeCol = new TableColumn<>( "Code" );
		codeCol.setCellValueFactory( new PropertyValueFactory< Code, String >(
				"code" ) );
		codeCol.setMinWidth( 400 );
		TableColumn< Code, Code > gotoCodeCol = new TableColumn<>( "Goto" );
		gotoCodeCol.setCellValueFactory( new PropertyValueFactory< Code, Code >(
				"gotoCode" ) );

		TableView< Code > table = new TableView<>();
		table.getColumns().addAll( serialCol, codeCol, gotoCodeCol );
		table.setItems( data );

		return table;

	}

	private ObservableList< Code > createFlow() {
		ObservableList< Code > data = FXCollections
				.observableArrayList( new Code( 10, "Start" ) );

		return data;
	}

}
